package magnet.processor;

import magnet.Instance;
import magnet.Registry;
import magnet.Scope;
import magnet.processor.common.CompilationException;
import magnet.processor.common.ValidationException;
import magnet.processor.instances.InstanceProcessor;
import magnet.processor.registry.RegistryProcessor;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.TypeElement;
import java.util.HashSet;
import java.util.Set;

@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class MagnetProcessor extends AbstractProcessor {

    private MagnetProcessorEnv env;
    private InstanceProcessor instanceProcessor;
    private RegistryProcessor registryProcessor;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnv) {
        super.init(processingEnv);
        env = new MagnetProcessorEnv(processingEnv);
        instanceProcessor = new InstanceProcessor(env);
        registryProcessor = new RegistryProcessor(env);
    }

    @Override
    public boolean process(
            Set<? extends TypeElement> annotations,
            RoundEnvironment roundEnv) {

        try {
            boolean instancesProcessed = instanceProcessor.process(roundEnv);
            boolean registryProcessed = registryProcessor.process(roundEnv);

            return instancesProcessed || registryProcessed;

        } catch (ValidationException e) {
            env.reportError(e);
            return false;
        } catch (CompilationException e) {
            env.reportError(e);
            return false;
        } catch (Throwable e) {
            env.reportError(e);
            e.printStackTrace();
            return false;
        }
    }

    @Override
    public Set<String> getSupportedAnnotationTypes() {
        Set<String> result = new HashSet<>();
        result.add(Instance.class.getName());
        result.add(Scope.class.getName());
        result.add(Registry.class.getName());
        return result;
    }
}

